/******************************************************************************* 
 * Copyright (C) 2012-2015 Microfountain Technology, Inc. All Rights Reserved. 
 * 
 * Unauthorized copying of this file, via any medium is strictly prohibited.   
 * Proprietary and confidential
 * 
 * Last Modified: 2015-9-18 15:19:50
 ******************************************************************************/
package cn.com.xy.sms.sdk.util;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipFile;

import android.content.Context;
import cn.com.xy.sms.sdk.constant.Constant;
import cn.com.xy.sms.sdk.dex.DexUtil;
import cn.com.xy.sms.sdk.log.LogManager;
import cn.com.xy.sms.sdk.net.HttpConnection;
/*SDK-464 hewengao 20160530 start*/
import android.content.res.AssetManager;
/*SDK-464 hewengao 20160530 end*/
import cn.com.xy.sms.sdk.Iservice.OnlineUpdateCycleConfigInterface;
/* SDK-428 huangzhiqiang 20160602 start */
import cn.com.xy.sms.sdk.Iservice.XyCallBack;
import cn.com.xy.sms.sdk.net.NetUtil;
/* SDK-428 huangzhiqiang 20160602 end */
import cn.com.xy.sms.sdk.net.util.Signaturer;
import cn.com.xy.sms.util.UUIDUtils;
/*SDK-654 hewengao 20161026 start*/
import java.util.concurrent.ConcurrentHashMap;
/*SDK-654 hewengao 20161026 end*/
public class FileUtils {

    private static String mTAG = "FileUtils";
    /*SDK-654 hewengao 20161026 start*/
    public static  ConcurrentHashMap<String,String>  mCacheJarFile = new ConcurrentHashMap<String,String>();
    public static boolean mIsLoaded = false;
    /*SDK-654 hewengao 20161026 end*/
    /* SDK-493 hewngao 20160618 start */
    public static void renameFile(String oldFilePath,String newFilePath){
		try {
			File file = new File(oldFilePath);
			if (file.exists()) {
				file.renameTo(new File(newFilePath));
			}
		} catch (Throwable e) {
			LogManager.e(Constant.TAG, "renameFile: ", e);
		}
    }
    public static void renameFile(String dir, String oldFileName,
            String newFileName) {
    	renameFile(dir+oldFileName,dir+newFileName);
    }

    public static void deleteDex(String prefix, String suffix, String nodelete) {
        try {
            File dexdir = Constant.getContext().getDir("outdex",
                    Context.MODE_PRIVATE);
            if (dexdir != null) {
                List<File> dexfileList = FileUtils.getFileList(
                        dexdir.getCanonicalPath(), prefix, suffix);
                mTAG = "deleteDex";
                FileUtils.deleteFile(dexfileList, nodelete);
            }
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "deleteDex: ", e);

        }
    }
    /* SDK-493 hewngao 20160618 end */
    // 判断jar文件是否存在，只判断有一个这种类型的jar存在，则是存在
    public static boolean isFileExists(String dir, String prefix, String suffix) {

        try {
            File root = new File(dir);
            if (!root.exists())
                root.mkdir();
            File[] files;
            files = root.listFiles(new MyFileFilter(prefix, suffix));
            if (files != null && files.length > 0) {
                return true;
            }
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "isFileExists: ", e);

        }
        return false;

    }

    public static String getFilePath(String dir, String prefix, String suffix) {

        try {
            /*SDK-654 hewengao 20161026 start*/
            String fName = mCacheJarFile.remove(prefix);
            if(fName != null){
                return dir+File.separator+fName;
            }
            /*SDK-667 zhaojiangwei 20161108 start*/
//            else{
//                if(mIsLoaded && prefix.startsWith("PU")){
//                    return "";
//                }
//            }
            /*SDK-667 zhaojiangwei 20161108 end*/
             /*SDK-654 hewengao 20161026 end*/
            File root = new File(dir);
            if (!root.exists())
                root.mkdir();
            File[] files;
            files = root.listFiles(new MyFileFilter(prefix, suffix));
            if (files != null && files.length > 0) {
                return files[0].getCanonicalPath();
            }else{
                /*SDK-674 hewengao 20161114 start*/
                LogManager.w(Constant.TAG,"not find file "+prefix,null);
                /*SDK-674 hewengao 20161114 end*/
            }
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "getFilePath: ", e);

        }
        return "";
    }
    /*SDK-654 hewengao 20161026 start*/
    public static void loadPUJarFile(){
        try {
            List<File> listFile = getFileList(Constant.getPARSE_PATH(), "PU", ".jar");
            if (listFile != null) {
                int size = listFile.size();
                for (int i = 0; i < size; i++) {
                    File tempFile = listFile.get(i);
                    String fileName = tempFile.getName();
                    int index = fileName.lastIndexOf("_");
                    if(index != -1) {
                        String subName = fileName.substring(0, index+1);
                        mCacheJarFile.put(subName, fileName);
                    }
                }
            }
            mIsLoaded =true;
        }catch(Throwable e){
            LogManager.e(Constant.TAG, "loadPUJarFile error: ", e);
        }
    }
    /*SDK-654 hewengao 20161026 end*/
    public static List<File> getFileList(String dir, String prefix,
            String suffix) {
        List<File> fileList = new ArrayList<File>();
        try {
            File root = new File(dir);
            if (!root.exists())
                root.mkdir();
            File[] files;
            files = root.listFiles(new MyFileFilter(prefix, suffix));
            if (files != null && files.length > 0) {
                fileList = java.util.Arrays.asList(files);
                return fileList;
            }
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "getFileList: ", e);

        }
        return fileList;
    }

    public static void deleteFile(String dir, String prefix, String suffix,
            String nodelete) {
        try {
            List<File> fileList = FileUtils.getFileList(dir, prefix, suffix);
            mTAG = "deleteFile";
            FileUtils.deleteFile(fileList, nodelete);
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "deleteFile: ", e);

        }

    }

    private static void deleteFile(List<File> list, String nodelete) {
        try {
            if (list != null && !list.isEmpty()) {
                Iterator<File> it = list.iterator();
                while (it != null && it.hasNext()) {
                    File file = it.next();
                    if (file.getName().equals(nodelete)) {
                    } else {
                        file.delete();
                    }
                }
            }

        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "deleteFile: ", e);

        }
    }

    public static boolean isFileExists(String sPath) {

        boolean flag = false;
        File file = new File(sPath);
        if (file.exists()) {
            flag = true;
        }
        return flag;
    }

    public static InputStream getInputStreamFromFile(String path) {

        File file = null;
        InputStream inputStream = null;
        try {
            file = new File(path);
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "getInputStreamFromFile: ", e);

        }
        return inputStream;
    }
    /*SDK-470 hewengao 20160630 start*/
    public static int downFile(String urlStr, String path, String fileName) {
         return downFileAndVerifyWithMd5(urlStr,path,fileName,false);
    }
    /**
     * if you use this method,you must make sure your file is name with md5.
     * 
     * @param urlStr
     * @param path
     * @param fileName
     * @return
     */
    public static int downFileAndVerifyWithMd5(String urlStr, String path,
            String fileName,boolean validMd5) {
   /*SDK-470 hewengao 20160630 end*/
        InputStream inputStream = null;
        HttpURLConnection urlConn = null;
        BufferedOutputStream outputStream = null;
        try {
            if (StringUtils.isNull(urlStr)) {
                return -1;
            }
            if (FileUtils.isFileExists(path + fileName)) {
                deleteFile(path + fileName);
            }

            if (FileUtils.isFileExists(path + fileName + ".temp")) {
                deleteFile(path + fileName + ".temp");
            }
            /*SDK-468 hewengao 20160630 start*/
            if (urlStr.startsWith("https") || urlStr.startsWith("HTTPS")) {
                urlConn = HttpConnection.createHttpsURLConnectionAndConnect(
                        urlStr, 0);
            } else {
                URL url = new URL(urlStr);
                urlConn = (HttpURLConnection) url.openConnection();
                /*SDK-619 zhaojiangwei 20160913 start */
                String referer = DexUtil.getOnLineConfigureData(OnlineUpdateCycleConfigInterface.CONFIG_URL_REFERER);
                if (StringUtils.isNull(referer)) {
                    referer = "bizport.cn/66dc91e8b78b1c284027a3eb1be0a70e";
                }
                urlConn.addRequestProperty("referer",  referer);
                /*SDK-619 zhaojiangwei 20160913 end */
            }
            
            urlConn.setConnectTimeout(60000);// 设置连接超时时间
            /* SDK-534 huangzhiqiang 20160712 start */
            urlConn.setReadTimeout(60000);
            /* SDK-534 huangzhiqiang 20160712 end */
            inputStream = urlConn.getInputStream();
            if(urlConn.getResponseCode() != 200){
            	return -1;
            }
            /*SDK-470 hewengao 20160531 start*/
            if(!validUrl(urlConn.getURL().toString(), urlStr)){
               //如果下载被网络重定向 状态也是200 这时?后面的是之前的下载地址 需要特殊处理
            	return -1;
            }
            /*SDK-470 hewengao 20160531 end*/
            /*SDK-468 hewengao 20160630 start*/
            int len, mHasRead = 0;
            byte[] buffer = new byte[8192];
            final long size = urlConn.getContentLength();
            File tempfile = new File(path + fileName + ".temp");
            /*SDK-757 songzhirong 20170407 start*/
            File parent = tempfile.getParentFile();
            if(parent!=null && !parent.exists()){
            	parent.mkdirs();
            }
            /*SDK-757 songzhirong 20170407 end*/

            outputStream = new BufferedOutputStream(new FileOutputStream(
                    tempfile));

            while (!Thread.interrupted()
                    && (len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
                mHasRead += len;
            }
            outputStream.flush();
            String fileMd5 = fileName.substring(0, fileName.lastIndexOf("."));

            if (mHasRead == size) {
                /*SDK-470 hewengao 20160630 start*/
            	boolean success = true;
            	if(validMd5){
                    String colMd5 = MD5FileUtil.getFileMD5String(tempfile);
                    if(!fileMd5.equals(colMd5)){
                    	success=false;
                    }
            	}
               /*SDK-472 hewengao 20160603 start */
                if (success || fileName.startsWith("duoqu_")) {
               /*SDK-472 hewengao 20160603 end */
                	
                /*SDK-470 hewengao 20160630 end*/
                    renameFile(path, fileName + ".temp", fileName);
                    return 0;
                }
            } else {
                if (FileUtils.isFileExists(path + fileName)) {
                    deleteFile(path + fileName);
                }
                if (FileUtils.isFileExists(path + fileName + ".temp")) {
                    deleteFile(path + fileName + ".temp");
                }
                return -1;
            }
        } catch (MalformedURLException e) {
            LogManager.e(Constant.TAG, "downFile: ", e);

            return -1;
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "downFile: ", e);

            return -1;
        } finally {
            close(inputStream);
            close(outputStream);
            closeUrlConnection(urlConn);
        }
        return -1;

    }
    public static File downFileFromInput(String path, String fileName,
            InputStream input) throws Exception {
        if (input == null) {
            return null;
        }

        File file = null;
        OutputStream output = null;
        try {
            file = new File(path + fileName);
            output = new FileOutputStream(file);
            byte buffer[] = new byte[1024];
            int bufferLength = 0;

            while ((bufferLength = input.read(buffer)) > 0) {
                output.write(buffer, 0, bufferLength);
            }

            output.flush();
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "downFileFromInput: ", e);
            if (FileUtils.isFileExists(path + fileName)) {
                deleteFile(path + fileName);
            }
        } finally {
            close(output);
            close(input);
            // try {
            // output.close();
            // } catch (IOException e) {
            // e.printStackTrace();
            // }
        }
        return file;
    }

    public static boolean deleteFile(String sPath) {
        boolean flag = false;
        try {
            if (!StringUtils.isNull(sPath)) {
                File file = new File(sPath);
                if (file.exists() && file.isFile()) {
                    file.delete();
                    flag = true;
                }
            }
        } catch (Throwable e) {
            // e.printStackTrace();
        }

        return flag;
    }

    /* SDK-396 huangzhiqiang 20160418 start */
    public static void deleteAllFile(File file) {
        try {
            if (file == null || !file.exists()) { // 判断文件是否存在
                return;
            }
            if (file.isFile()) { // 判断是否是文件
                file.delete(); // delete()方法 你应该知道 是删除的意思;
            } else if (file.isDirectory()) { // 否则如果它是一个目录
                File files[] = file.listFiles(); // 声明目录下所有的文件 files[];
                if (files == null) {
                    file.delete();
                    return;
                }
                for (int i = 0; i < files.length; i++) { // 遍历目录下所有的文件
                    deleteAllFile(files[i]); // 把每个文件 用这个方法进行迭代
                }
                file.delete();
            }
        } catch (Throwable ex) {
            LogManager.e(Constant.TAG, "deleteAllFile: ", ex);
        }
    }

    public static void deleteAllFile(String filePath) {
        deleteAllFile(new File(filePath));
    }
    /* SDK-396 huangzhiqiang 20160418 end */

    /**
     * 获取文件流数据
     * 
     * @param filePath
     * @return
     * @throws Throwable
     */
    public static byte[] getFileBytes(String filePath) throws Exception {
        InputStream is = new FileInputStream(filePath);
        return getInputStream(is);
    }

    public static String getStringFromInputStream(InputStream is) {
        try {
            byte[] bt = getInputStream(is);
            String response = new String(bt, "UTF-8");
            return response;
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "getStringFromInputStream: ", e);

        }
        return "";

    }

    public static byte[] getInputStream(InputStream is) throws Exception {
        byte[] buffer = new byte[512 * 5];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DataInputStream dis = null;
        try {
            dis = new DataInputStream(is);
            int len = -1;
            while ((len = dis.read(buffer)) > 0) {
                bos.write(buffer, 0, len);
            }
            buffer = bos.toByteArray();
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "getInputStream: ", e);

        } finally {
            close(dis);
            close(is);
            close(bos);
        }
        
        return buffer;
    }

    /**
     * 关闭流
     * 
     * @param close
     */
    public static void close(Closeable close) {
        if (close != null) {
            try {
                close.close();
            } catch (Throwable e) {
//                e.printStackTrace();
                LogManager.e(Constant.TAG, "close: ", e);

            }
        }
    }

    public static void closeUrlConnection(HttpURLConnection urlConn) {
        try {
            if (urlConn != null) {
                urlConn.disconnect();
            }
        } catch (Throwable e) {
//            e.printStackTrace();
            LogManager.e(Constant.TAG, "closeUrlConnection: ", e);

        }
    }

    public static void close(ZipFile close) {
        if (close != null) {
            try {
                close.close();
            } catch (Throwable e) {
//                e.printStackTrace();
                LogManager.e(Constant.TAG, "close: ", e);

            }
        }
    }

    /**
     * 获取Assets文件夹下指定txt文件的内容，文件不存在或内容为空时返回"-1"
     * 
     * @param txtFileName
     *            txt文件名 例："duoqu_drawable_version.txt"
     * @return 文件不存在或内容为空时返回"-1"，否则返回文件内容
     */
    public static String getAssetsTxtFileContent(String txtFileName) {
        InputStream is = null;
        try {
            /*SDK-464 hewengao 20160530 start*/
            is =getAssetManager().open(txtFileName);
            /*SDK-464 hewengao 20160530 end*/
            int size = is.available();
            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();
            String version = new String(buffer, "GB2312");
            if (!StringUtils.isNull(version)) {
                return version;
            }
        } catch (IOException e) {
            LogManager.e(Constant.TAG, "getAssetsTxtFileContent: ", e);

        } catch (Throwable e) {
//            ex.printStackTrace();
            LogManager.e(Constant.TAG, "getAssetsTxtFileContent: ", e);

        } finally {
            close(is);
        }
        return "-1";
    }

    /**
     * 获取Assets文件夹下指定txt文件的内容
     * 
     * @param txtFileName
     *            txt文件名 例："duoqu_drawable_version.txt"
     * @return
     */
    public static List<String> getAssetsTxtFileListInfo(String txtFileName) {
        InputStream is = null;
        BufferedReader bufferedReader = null;
        try {
            /*SDK-464 hewengao 20160530 start*/
            is = FileUtils.getAssetManager().open(txtFileName);
            /*SDK-464 hewengao 20160530 end*/
            bufferedReader = new BufferedReader(new InputStreamReader(is,
                    "GB2312"));
            String lineContent = null;
            List<String> infoList = new ArrayList<String>();
            while ((lineContent = bufferedReader.readLine()) != null) {
                infoList.add(lineContent);
            }
            return infoList;
        } catch (IOException ex) {
        } catch (Throwable ex) {
//            ex.printStackTrace();
        	LogManager.e(Constant.TAG, "getAssetsTxtFileListInfo", ex);
        } finally {
            close(bufferedReader);
            close(is);
        }
        return null;
    }
    
    public static String getAssetsPver(String txtFileName) {
        InputStream is = null;
        BufferedReader bufferedReader = null;
        try {
            /*SDK-464 hewengao 20160530 start*/
            is = FileUtils.getAssetManager().open(txtFileName);
            /*SDK-464 hewengao 20160530 end*/
            bufferedReader = new BufferedReader(new InputStreamReader(is,
                    "GB2312"));
            String lineContent = null;
         
            while ((lineContent = bufferedReader.readLine()) != null) {
            	if(StringUtils.isNull(lineContent) || (lineContent.indexOf("PVER:")==-1)){
            		continue;
            	}
            	String pver = lineContent.substring(5).trim();
            	return pver;
            }
           
        } catch (Throwable ex) {
//            ex.printStackTrace();
        	LogManager.e(Constant.TAG, "getAssetsPver", ex);
        } finally {
            close(bufferedReader);
            close(is);
        }
        return "";
    }

    /* SDK-570 huangzhiqiang 20160802 start */
    public static String getXCode1() {
        return "3634343535373433";
    }
    /* SDK-570 huangzhiqiang 20160802 end */

    /*SDK-464 hewengao 20160530 start*/
    public static AssetManager getAssetManager(){
    	AssetManager assetManager = null;
    	try{
    	    assetManager = DuoquUtils.getSdkDoAction().getExtendAssetManager();
    	}catch(Exception e){
    		LogManager.e(Constant.TAG, "getExtendAssetManager", e);
    	}
    	if(assetManager == null){
    	    assetManager =Constant.getContext().getResources().getAssets();
    	}
    	return assetManager;
    }
    /*SDK-464 hewengao 20160530 end*/
    
    /*SDK-470 hewengao 20160531 start*/
    private static boolean validUrl(String newUrl,String oldUrl){
    	try{
	    	if(newUrl.length() > oldUrl.length()){
	        	int index = newUrl.indexOf("?");
	        	if(index != -1){
	        		newUrl = newUrl.substring(index+1);
	            	String tempOldUrl =oldUrl.replaceFirst("https://", "");
	            	tempOldUrl =tempOldUrl.replaceFirst("HTTPS://", "");
	            	tempOldUrl =tempOldUrl.replaceFirst("http://", "");
	            	tempOldUrl =tempOldUrl.replaceFirst("HTTP://", "");
	            	if(newUrl.indexOf(tempOldUrl) != -1){
	            		return false;
	            	}
	        	}
	        }
	    	return true;
    	}catch(Throwable e){
    		LogManager.e("xiaoyuan", "FileUtils.validUrl: ", e);
    	}
    	return false;
    }  
    /*SDK-470 hewengao 20160531 end*/

    /* SDK-428 huangzhiqiang 20160601 start */
    /**
     * 下载文件并返回文件File对象
     * 
     * @param ctx
     * @param serverUrl 文件所在服务器url
     * @param fileName 文件名称
     * @param folderPath 存放文件夹
     * @param checkMD5 文件下载回来后是否进行MD5校验（文件名必须以MD5命名才能支持MD5校验）
     * @param callBack 
     *            *index0(状态):
     *                CallBackState.DOWNLOAD_COMPLETE:当前线程或新线程，成功下载文件
     *                CallBackState.DOWNLOAD_FAILED:当前线程或新线程，文件下载失败
     *                CallBackState.ERROR:存在异常，文件下载失败
     *            *index1:logoName 
     *            *index2:(index0 == CallBackState.DOWNLOAD_COMPLETE):文件的File对象 
     *                    (index0 == CallBackState.DOWNLOAD_FAILED):"download failed"
     *                    (index0 == CallBackState.ERROR):String类型 异常信息
     * @return
     */
    public static File downFile(Context ctx, String serverUrl, String fileName, String folderPath,
            boolean checkMD5, XyCallBack callBack) {
        try {
            if (!NetUtil.checkAccessNetWork(2)) {
                throw new Exception("no network");
            }

            File file = null;
            String logoUrl = serverUrl + fileName;
            int result = downFileAndVerifyWithMd5(logoUrl, folderPath, fileName, checkMD5);
            if (result == 0) {// 下载成功
                file = new File(folderPath + fileName);
            }

            if (file != null && file.exists()) {
                XyUtil.doXycallBackResult(callBack, CallBackState.DOWNLOAD_COMPLETE, fileName, file);
            } else {
                file = null;
                XyUtil.doXycallBackResult(callBack, CallBackState.DOWNLOAD_FAILED, fileName, "download failed");
            }
            return file;
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "FileUtils downFile error:", e);
            XyUtil.doXycallBackResult(callBack, CallBackState.ERROR, fileName, e.getMessage());
        }
        return null;
    }
    /* SDK-428 huangzhiqiang 20160601 end */
}
